package com.ycl.bookstore.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONNull;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ycl.bookstore.DTO.CommentDTO;
import com.ycl.bookstore.DTO.FriendCommentsDTO;
import com.ycl.bookstore.DTO.ShowDTO;
import com.ycl.bookstore.DTO.UserDTO;
import com.ycl.bookstore.common.Result;
import com.ycl.bookstore.mapper.FriendCommentsMapper;
import com.ycl.bookstore.mapper.FriendsMapper;
import com.ycl.bookstore.mapper.UserMapper;
import com.ycl.bookstore.pojo.FriendComments;
import com.ycl.bookstore.pojo.Friends;
import com.ycl.bookstore.pojo.MyMessage;
import com.ycl.bookstore.pojo.User;
import com.ycl.bookstore.service.FriendService;
import com.ycl.bookstore.utils.AliOssUtil;
import com.ycl.bookstore.utils.MyThreadLocal;
import jakarta.annotation.Resource;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

import static com.ycl.bookstore.utils.RabbitMqConstants.FRIENDS_LIKE_QUEUE;
import static com.ycl.bookstore.utils.RedisConstants.*;

/**
 *
 */
@Service
public class FriendServiceImpl extends ServiceImpl<FriendsMapper, Friends> implements FriendService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private FriendsMapper friendMapper;

    @Resource
    private FriendCommentsMapper friendCommentsMapper;

    @Resource
    private UserMapper userMapper;

    @RabbitListener(queues = FRIENDS_LIKE_QUEUE)
    @RabbitHandler
    public void receiverMessageWithLike(MyMessage message) {
        Long friendId = message.getFriendId();
        Long userId = message.getUserId();
        String key = FRIENDS_ISLIKE_KEY + friendId;
        // 查询redis中该文章是否有用户的点赞信息
        Boolean res = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        UpdateWrapper<Friends> wrapper = new UpdateWrapper<>();
        if (res) {// 存在用户点赞信息  表示该用户正在取消点赞
            //数据库点赞数-1
            wrapper.setSql("likes=likes-1").eq("id", friendId);
            int count = friendMapper.update(null, wrapper);
            if (count > 0) {
                stringRedisTemplate.opsForSet().remove(key, userId.toString());
            }
            // 修改redis中缓存的点赞数
            String oldFriendJSON = stringRedisTemplate.opsForValue().get(FRIENDS_LIST_KEY + friendId);
            Friends friends = JSONUtil.toBean(oldFriendJSON, Friends.class);
            String newFriendJSON = JSONUtil.toJsonStr(friends.setLikes(friends.getLikes() - 1));
            stringRedisTemplate.opsForValue().set(FRIENDS_LIST_KEY + friendId, newFriendJSON);
        } else {
            // 用户点赞
            // 数据库点赞数+1
            wrapper.setSql("likes=likes+1").eq("id", friendId);
            int count = friendMapper.update(null, wrapper);
            if (count > 0) {
                stringRedisTemplate.opsForSet().add(key, userId.toString());
            }
            // 修改redis中缓存的点赞数
            String oldFriendJSON = stringRedisTemplate.opsForValue().get(FRIENDS_LIST_KEY + friendId);
            Friends friends = JSONUtil.toBean(oldFriendJSON, Friends.class);
            String newFriendJSON = JSONUtil.toJsonStr(friends.setLikes(friends.getLikes() + 1));
            stringRedisTemplate.opsForValue().set(FRIENDS_LIST_KEY + friendId, newFriendJSON);
        }
    }

    /**
     * 得到朋友圈列表
     *
     * @return
     */
    @Override
    public Result getFriendList() {
        List<Friends> friendsList = new LinkedList<>();
        // 判断redis缓存中是否存在文章列表
        Boolean res = stringRedisTemplate.keys(FRIENDS_LIST_KEY + "*").isEmpty();
        if (res) { // 不存在文章列表 从数据库中查询
            friendsList = friendMapper.selectList(null);
            for (Friends friends : friendsList) {
                // 设置friends的头像  昵称  是否为该文章点赞
                setFriendProperty(friends);
                // 将文章的信息存入redis中
                String friendJSON = JSONUtil.toJsonStr(friends);
                stringRedisTemplate.opsForValue().set(FRIENDS_LIST_KEY + friends.getId(), friendJSON);
                // 将问文章的评论列表存入redis中
                List<FriendCommentsDTO> friendComments = getFriendComments(friends);
                for (FriendCommentsDTO friendComment : friendComments) {
                    // 采用redis的list数据类型 每一条评论都存入redis中
                    String commentJSON = JSONUtil.toJsonStr(friendComment);
                    stringRedisTemplate.opsForList().rightPush(FRIENDS_LIST_KEY + friends.getId() + ":" + "comment", commentJSON);
                }
                // 文章内容下加入评论
                friends.setFriendComments(friendComments);
            }
            Collections.reverse(friendsList);
            return Result.success(friendsList);
        }
        // 不为空从redis中取出数据
        List<Integer> idList = friendMapper.selectIdList();
        for (Integer id : idList) {
            // 从redis中获取文章和评论信息
            String friendSJON = stringRedisTemplate.opsForValue().get(FRIENDS_LIST_KEY + id);
            List<String> list = stringRedisTemplate.opsForList().range(FRIENDS_LIST_KEY + id + ":" + "comment", 0, -1);
            // 评论列表信息
            if (friendSJON != null && list != null) {
                Friends friends = JSONUtil.toBean(friendSJON, Friends.class);
                // 得到评论区列表信息
                List<FriendCommentsDTO> commentsList = new LinkedList<>();
                for (String comment : list) {
                    FriendCommentsDTO friendComments = JSONUtil.toBean(comment, FriendCommentsDTO.class);
                    commentsList.add(friendComments);
                }
                // 给朋友圈属性赋值
                setFriendProperty(friends);
                friends.setFriendComments(commentsList);
                friendsList.add(friends);
            }
        }
        // 从redis中查询文章内容
        Collections.reverse(friendsList);
        return Result.success(friendsList);
    }

    /**
     * 用户发送评论
     *
     * @param commentDTO
     * @return
     */
    @Override
    @Transactional
    public Result sendComment(CommentDTO commentDTO) {
        // 向数据库中插入信息
        FriendComments friendsComment = getFriendsComment(commentDTO);
        int count = friendCommentsMapper.insert(friendsComment);
        // 评论数量+1
        UpdateWrapper<Friends> wrapper = new UpdateWrapper<>();
        wrapper.setSql("comments=comments+1").eq("id", commentDTO.getId());
        count += friendMapper.update(null, wrapper);
        if (count < 2) {
            return Result.fail("评论失败");
        }
        // 向redis存入数据
        FriendCommentsDTO friendCommentsDTO = new FriendCommentsDTO();
        User user = getUser(MyThreadLocal.getUser().getId());
        friendCommentsDTO.setIcon(user.getIcon());
        friendCommentsDTO.setNickName(user.getNickName());
        friendCommentsDTO.setText(commentDTO.getText());
        // 转化为json对象
        String s = JSONUtil.toJsonStr(friendCommentsDTO);
        String key = FRIENDS_LIST_KEY + commentDTO.getId() + ":" + "comment";
        stringRedisTemplate.opsForList().rightPush(key, s);
        return Result.success();
    }

    @Override
    public Result showPost(MultipartFile[] files,String title) {
        // 获取文件字符串
        String fileStr = getFileStr(files);
        Friends friends = getFriendsPost(fileStr,title);
        // 插入数据库中
        int count = friendMapper.insert(friends);
        if (count < 1) {
            Result.fail("发表失败");
        }
        // 存入redis的缓存中
        String key = FRIENDS_LIST_KEY + (friends.getId());
        String friendsJson = JSONUtil.toJsonStr(friends);
        stringRedisTemplate.opsForValue().set(key, friendsJson);
        return Result.success();
    }

    private List<FriendCommentsDTO> getFriendComments(Friends friends) {
        List<FriendCommentsDTO> commentsList = new LinkedList<>();
        // 获取朋友圈id
        Long friendsId = friends.getId();
        // 查询该文章的评论列表
        LambdaQueryWrapper<FriendComments> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FriendComments::getFriendId, friendsId);
        List<FriendComments> friendComments = friendCommentsMapper.selectList(wrapper);
        for (FriendComments friendComment : friendComments) {
            // 根据用户id查询用户信息
            User user = getUser(friendComment.getUserId());
            String nickName = user.getNickName();
            String icon = user.getIcon();
            String text = friendComment.getText();
            commentsList.add(new FriendCommentsDTO(user.getId(), nickName, icon, text));
        }
        return commentsList;
    }

    // 处理朋友圈列表点赞的问题(处理每个用户的对每个文章的点赞)
    private boolean isFriendLike(Friends friends) {
        // 获取当前的用户id
        Long userId = MyThreadLocal.getUser().getId();
        return stringRedisTemplate.opsForSet().isMember(FRIENDS_ISLIKE_KEY + friends.getId(), userId.toString());
    }

    // 获取用户信息
    private User getUser(Long id) {
        return userMapper.selectById(id);
    }

    private void setFriendProperty(Friends friends) {
        // 获取发布文章的作者信息
        User user = getUser(friends.getUserId());
        // 设置昵称
        friends.setNickName(user.getNickName());
        // 设置头像
        friends.setIcon(user.getIcon());
        // 当前用户是否为文章点过赞
        friends.setIsLike(this.isFriendLike(friends));
    }

    // 得到评论对象 (用户评论)
    private FriendComments getFriendsComment(CommentDTO commentDTO) {
        FriendComments friendComments = new FriendComments();
        // 获取当前用户id
        Long userId = MyThreadLocal.getUser().getId();
        friendComments.setUserId(userId);
        friendComments.setFriendId(commentDTO.getId());
        friendComments.setText(commentDTO.getText());
        friendComments.setCommentTime(LocalDateTime.now());
        friendComments.setCreatedAt(LocalDateTime.now());
        return friendComments;
    }

    public Friends getFriendsPost(String files,String title) {
        // 获取当前用户
        UserDTO user = MyThreadLocal.getUser();
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        return Friends.builder()
                .userId(user.getId())
                .icon(user.getIcon())
                .content(title)
                .images(files)
                .comments(0)
                .likes(0)
                .isPublic(1)
                .publishTime(now)
                .createdAt(now)
                .updatedAt(now).build();
    }

    /**
     * 处理照片 将照片集合转化成字符串
     *
     * @return
     */
    public String getFileStr(MultipartFile[] files){
        // 存放照片路径集合
        List<String> list=new ArrayList<>();
        for (MultipartFile file : files) {
            try {
                // 原始文件名
                String originalFilename = file.getOriginalFilename();
                int lastIndexOf = originalFilename.lastIndexOf(".");
                String extension = originalFilename.substring(lastIndexOf);
                // 构建新文件名称
                String objectName = UUID.randomUUID().toString() + extension;

                //文件的请求路径
                String filePath = AliOssUtil.upload(file.getBytes(), objectName);
                list.add(filePath);
        }catch (IOException e){
                e.getStackTrace();
            }
        }
        return StringUtils.join(list, ",");
    }
}




